package org.issaclu.springbootmybatis.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.node.*;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.List;

public class JsonUtil {

    private static final ObjectMapper OBJECT_MAPPER = JsonMapper.builder()
            .disable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS)
            .build()
            .setSerializationInclusion(JsonInclude.Include.NON_NULL)
            .setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))
            .enable(SerializationFeature.INDENT_OUTPUT)
            .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);



    /**
     * 对象转json string
     *
     * @param data 需要转换的对象
     * @return json string
     * @throws JsonProcessingException e
     */
    public static String toString(Object data) throws JsonProcessingException {
        if (data == null) {
            return null;
        }
        if (data instanceof String) {
            return (String) data;
        }
        return OBJECT_MAPPER.writeValueAsString(data);
    }

    /**
     * 转为json 数据对应的 byte数组
     *
     * @param data 需要转换的数组
     * @return bytes
     * @throws JsonProcessingException e
     */
    public static byte[] toBytes(Object data) throws JsonProcessingException {
        String result = toString(data);
        if (result == null) {
            return new byte[0];
        }
        return result.getBytes();
    }

    /**
     * json 字符串转为Json
     *
     * @param json  json串
     * @param clazz Class类
     * @param <T>   要转为哪种类的实例
     * @return 对象
     */
    public static <T> T toJavaType(String json, Class<T> clazz) throws JsonProcessingException {
        if (json == null) {
            return null;
        }
        if (json.length() < 2) {
            return null;
        }
        if (clazz == String.class) {
            return (T) json;
        }
        return OBJECT_MAPPER.readValue(json, clazz);
    }

    /**
     * json 字符串转为java 对象
     *
     * @param is 流
     * @param clazz Class类
     * @param <T>   要转为哪种类的实例
     * @return 对象
     */
    public static <T> T toJavaType(InputStream is, Class<T> clazz) throws IOException {
        if (is == null) {
            return null;
        }
        return OBJECT_MAPPER.readValue(is, clazz);
    }

    /**
     * json 字符串转为Json
     *
     * @param json  json串
     * @param type Class类
     * @param <T>   要转为哪种类的实例
     * @return 对象
     */
    public static <T> T toJavaType(String json, Type type) throws JsonProcessingException {
        if (json == null) {
            return null;
        }
        if (json.length() < 2) {
            return null;
        }
        if (type == String.class) {
            return (T) json;
        }
        return OBJECT_MAPPER.readValue(json, OBJECT_MAPPER.getTypeFactory().constructType(type));
    }


    /**
     * json 字符串转为java 对象
     *
     * @param is 流
     * @param type  Type
     * @param <T>   要转为哪种类的实例
     * @return 对象
     */
    public static <T> T toJavaType(InputStream is, Type type) throws IOException {
        if (is == null) {
            return null;
        }
        return OBJECT_MAPPER.readValue(is, OBJECT_MAPPER.getTypeFactory().constructType(type));
    }

    public static <T> T transformType(Object source, Class<T> targetClass) throws JsonProcessingException {
        return toJavaType(toString(source), targetClass);
    }

    /**
     * 将 json array 字符串转为 list 并指定泛型
     *
     * @param json   json 串
     * @param tClass List 泛型class
     * @param <T>    泛型
     * @return e
     */
    public static <T> List<T> toJavaList(String json, Class<T> tClass) throws JsonProcessingException {
        return OBJECT_MAPPER.readValue(json, OBJECT_MAPPER.getTypeFactory().constructParametricType(List.class,
                tClass));
    }

    public static <T> List<T> transformType(Collection<?> source, Class<T> eleClass) throws JsonProcessingException {
        if (source == null || source.isEmpty()) {
            return null;
        }
        return toJavaList(toString(source), eleClass);
    }


    /**
     * 创建一个json对象
     *
     * @return json
     */
    public static ObjectNode makeJsonObject() {
        return OBJECT_MAPPER.createObjectNode();
    }

    /**
     * 创建一个json数组对象
     *
     * @return json array
     */
    public static ArrayNode makeJsonArray() {
        return OBJECT_MAPPER.createArrayNode();
    }

    /**
     * 从字符串读取json
     *
     * @param jsonStr json 字符串
     * @return Json
     * @throws JsonProcessingException e
     */
    public static JsonNode readJson(String jsonStr) throws JsonProcessingException {
        if (jsonStr == null || jsonStr.length() < 2) {
            return null;
        }
        JsonNode node = OBJECT_MAPPER.readTree(jsonStr);

        if (node.isObject() || node.isArray()) {
            return node;
        } else {
            throw new RuntimeException("参数不是一个json 字符串！！");
        }
    }

    public static JsonNode readJson(InputStream inputStream) throws IOException {
        JsonNode node = OBJECT_MAPPER.readTree(inputStream);
        if (node.isObject() || node.isArray()) {
            return node;
        } else {
            throw new RuntimeException("参数不是一个json 字符串！！");
        }
    }

    public static JsonNode readJson(File file) throws IOException {
        if (file == null || !file.exists() || !file.canRead()) {
            return null;
        }

        JsonNode node = OBJECT_MAPPER.readTree(file);
        if (node.isObject() || node.isArray()) {
            return node;
        } else {
            throw new RuntimeException("参数不是一个json 字符串！！");
        }
    }

    public static ObjectNode readJsonObject(String jsonStr) throws JsonProcessingException {

        JsonNode jn = readJson(jsonStr);
        if (jn instanceof ObjectNode jo) {
            return jo;
        } else {
            throw new RuntimeException("参数不是一个json object 字符串！！");
        }

    }

    public static ObjectNode readJsonObject(File file) throws IOException {
        JsonNode jn = readJson(file);
        if (jn instanceof ObjectNode jo) {
            return jo;
        } else {
            throw new RuntimeException("参数不是一个json object 字符串！！");
        }
    }

    public static ObjectNode readJsonObject(InputStream inputStream) throws IOException {
        JsonNode jn = readJson(inputStream);
        if (jn instanceof ObjectNode jo) {
            return jo;
        } else {
            throw new RuntimeException("参数不是一个json object 字符串！！");
        }
    }

    public static ArrayNode readJsonArray(File file) throws IOException {
        if (file == null || !file.exists() || !file.canRead()) {
            return null;
        }

        JsonNode node = OBJECT_MAPPER.readTree(file);
        if (node instanceof ArrayNode) {
            return (ArrayNode) node;
        } else {
            throw new RuntimeException("参数不是一个json array 字符串！！");
        }
    }

    /**
     * 从字符串读取jsonArray
     *
     * @param jsonStr jsonArray 字符串
     * @return JsonArray
     * @throws JsonProcessingException e
     */
    public static ArrayNode readJsonArray(String jsonStr) throws JsonProcessingException {
        JsonNode node = OBJECT_MAPPER.readTree(jsonStr);

        if (node instanceof ArrayNode) {
            return (ArrayNode) node;
        } else {
            throw new RuntimeException("参数不是一个json 数组形式的 字符串！！");
        }
    }

    /**
     * 获取 String 值，但凡没有这个key,或者 key对应的值不是一个 基本类型节点，都返回 null
     *
     * @param json json
     * @param key  key
     * @return String value
     */
    public static String getString(ObjectNode json, String key) {
        if (json == null || key == null) {
            return null;
        }

        if (json.has(key)) {
            JsonNode node = json.get(key);
            if (node instanceof NumericNode || node instanceof BooleanNode || node instanceof TextNode) {
                return node.asText();
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * 在 json 中没有 指定属性时返回自定义的默认值 {@param defaultValue}
     *
     * @param json         json
     * @param key          key
     * @param defaultValue 默认值
     * @return value
     */
    public static String getString(ObjectNode json, String key, String defaultValue) {
        String value = getString(json, key);
        return value == null ? defaultValue : value;
    }


    /**
     * 在 json中 获取 int 型属性
     *
     * @param json json
     * @param key  key
     * @return value
     */
    public static int getInteger(ObjectNode json, String key) {
        ValueNode valueNode = getValueNode(json, key);

        if (valueNode instanceof NumericNode) {
            NumericNode n = (NumericNode) valueNode;
            return n.asInt();
        } else {
            throw new IllegalArgumentException("key :" + key + " is not a number");
        }

    }

    /**
     * 在 {@code json}中 获取 int 型属性,在没有这个 {@code key} 或者对应属性不是int时 返回 {@code defaultValue}
     *
     * @param json         json
     * @param key          key
     * @param defaultValue default value
     * @return value or default value
     */
    public static int getInteger(ObjectNode json, String key, int defaultValue) {
        try {
            return getInteger(json, key);
        } catch (Exception e) {
            return defaultValue;
        }

    }


    /**
     * 在 json中 获取 long 型属性
     *
     * @param json json
     * @param key  key
     * @return value
     */
    public static long getLong(ObjectNode json, String key) {
        ValueNode valueNode = getValueNode(json, key);

        if (valueNode instanceof NumericNode) {
            NumericNode n = (NumericNode) valueNode;
            return n.asLong();
        } else {
            throw new IllegalArgumentException("key :" + key + " is not a number");
        }

    }

    /**
     * 在 {@code json}中 获取 long 型属性,在没有这个 {@code key} 或者对应属性不是long 时 返回 {@code defaultValue}
     *
     * @param json         json
     * @param key          key
     * @param defaultValue default value
     * @return value or default value
     */
    public static long getLong(ObjectNode json, String key, long defaultValue) {
        try {
            return getLong(json, key);
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * 获取json 中嵌套的 json对象
     *
     * @param json json
     * @param key  key
     * @return e
     */
    public static ObjectNode getJson(ObjectNode json, String key) {

        if (json == null || key == null) {
            return null;
        }

        if (json.has(key)) {
            JsonNode node = json.get(key);
            return node.isObject() ? (ObjectNode) node : null;
        } else {
            return null;
        }
    }

    /**
     * 获取json 中的值
     *
     * @param json json
     * @param key  key
     * @return e
     */
    public static ObjectNode getJsonObject(ObjectNode json, String key) {

        if (json == null || key == null) {
            throw new NullPointerException("json or key can not be null");
        }

        if (json.has(key)) {
            JsonNode node = json.get(key);
            if (node.isObject()) {
                return (ObjectNode) node;
            } else {
                throw new IllegalArgumentException("key :" + key + " is not a object node");
            }
        } else {
            throw new NullPointerException("json not contain this key :" + key);
        }
    }

    /**
     * 获取json 中嵌套的 json对象
     *
     * @param json json
     * @param key  key
     * @return e
     */
    public static ValueNode getValueNode(ObjectNode json, String key) {

        if (json == null || key == null) {
            throw new NullPointerException("json or key can not be null");
        }

        if (json.has(key)) {
            JsonNode node = json.get(key);
            if (node.isValueNode()) {
                return (ValueNode) node;
            } else {
                throw new IllegalArgumentException("key :" + key + " is not a value node");
            }

        } else {
            throw new NullPointerException("json not contain this key :" + key);
        }
    }


    public static TreeNode getTreeNode(ObjectNode json, String key) {
        if (json == null || key == null) {
            return null;
        }

        if (json.has(key)) {
            return json.get(key);
        } else {
            return null;
        }
    }
}

